package blogs.eidos.cloud.framework.core.aspect;

import net.bigdata.cloud.framework.common.exception.UnAuthorizedException;
import net.bigdata.cloud.framework.core.annotation.ExtApiIdempotent;
import net.bigdata.cloud.framework.core.annotation.ExtApiToken;
import net.bigdata.cloud.framework.shiro.cache.JwtTokenRedisService;
import net.bigdata.cloud.framework.util.LoginUtil;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * AOP切面
 * 完成2个功能：
 * 1)判断接口方法是否有ExtApiToken注解,如果有自动在HttpServletRequest中添加token字段值
 * 2)判断接口方法是否有ExtApiIdempotent注解,如果有则校验token
 *
 * @author ： Eidos
 * @date ：Created in 2021/4/21
 * @description：
 * @modified By：
 * @version: 1.0
 */
@Component
//@Aspect
public class ExtApiIdempotentAop {


    @Resource
    private JwtTokenRedisService loginRedisService;

    /**
     * Pointcut表达式
     *
     */
    @Pointcut("execution(public * net.bigdata.cloud.web.controller.*.*(..))")
    public void extApiIdeAop() {

    }

    /**
     * 对ExtApiToken注解的接口 自动在HttpServletRequest中添加token字段值
     *
     * @param point
     */
    @Before("extApiIdeAop()")
    public void before(JoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        ExtApiToken annotation = signature.getMethod().getAnnotation(ExtApiToken.class);
        if (annotation != null) {
            getRequest().setAttribute("token", LoginUtil.getLoginUser().getToken());
        }
    }

    /**
     * 环绕通知
     *
     * @param proceedingJoinPoint
     */
    @Around("extApiIdeAop()")
    public Object doBefore(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //判断方法上是否有ExtApiIdempotent注解
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        ExtApiIdempotent extApiIdempotent = signature.getMethod().getDeclaredAnnotation(ExtApiIdempotent.class);
        if (extApiIdempotent != null) {
            //放行
            return proceedingJoinPoint.proceed();
        }
        // 代码步骤：
        // 1.获取令牌 存放在请求头中
        HttpServletRequest request = getRequest();
        String valueType = extApiIdempotent.type();
        if (StringUtils.isEmpty(valueType)) {
            throw new UnAuthorizedException("token为空");
        }

        String token = null;
        String head = "head";
        if (head.equalsIgnoreCase(valueType)) {
            //extApiIdempotent
            token = request.getHeader("token");
        } else {
            token = request.getParameter("token");
        }
        if (StringUtils.isEmpty(token)) {
            throw new UnAuthorizedException("token为空");
        }
        boolean tokenOk = loginRedisService.exists(token);
        if (!tokenOk) {
            getResponse("请勿重复提交！");
            return null;
        }
        Object proceed = proceedingJoinPoint.proceed();
        loginRedisService.deleteToken(token);
        return proceed;
    }

    /**
     *
     * @return HttpServletRequest
     */
    public HttpServletRequest getRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        return request;
    }

    /**
     *
     * @param  msg
     */
    public void getResponse(String msg) throws IOException {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = attributes.getResponse();
        PrintWriter writer = response.getWriter();
        writer.write(msg);
        writer.close();
    }


}
